/*
 * Party.cpp
 *
 *  Created on: 2013. 9. 26.
 *      Author: jjaehuny
 */

#include "Party.h"

#include "../User.h"
#include "Static.h"
#include "Battle.h"
#include "Equip.h"

#include "../NGameLog/Static.h"
#include "../NResource/Static.h"

namespace ProjectZ { namespace NLogic {

Party::Party() : _master(NULL), _acceptCount(0), _refuseCount(0), _startBattle(false), _readyCount(0), _state(State::__NONE__),
		_tick(0), _interval(0), _roomWaitEndTime(0), _createHpBuffCoolTimeCount(0), _createHpBuffKey(0),
		_healBuffBattle(NULL), _healBuffTotalTimeCount(0), _isChangeMaster(false), _pvpDelayUser(NULL), _pkAIPlayUser(NULL), _space(NULL)
{
}

Party::~Party() {
}

void
Party::Initialize()
{
	_master = NULL;
	_clsAllUserTree.clear();
	_acceptCount = 0;
	_refuseCount = 0;
	_startBattle = false;
	_readyCount = 0;
	_state = State::__NONE__;

	_clsInviteUserTree.clear();
	_clsAcceptUserTree.clear();
	_clsReadyUserTree.clear();
	_playUserTree.clear();


	_roomWaitEndTime = 0;

	_createHpBuffCoolTimeCount = 0;
	_createHpBuffKey = 0;

	_healBuffBattle = NULL;

	_healBuffTotalTimeCount = 0;



	_isChangeMaster = false;
	_pvpDelayUser = NULL;
	_space = NULL;
}

void
Party::Finalize()
{
	//this->killTimer(static_cast<int>(_state));
	//this->killTimer(this);
	::Dispatcher::GETTIMER()->KillTimer(this);
}

void
Party::Open(User * pMaster)
{
	_master = pMaster;
	_master->SetParty(this);
	this->EnterUser(_master);
}

User *
Party::GetMaster()
{
	return _master;
}

bool
Party::EnterUser(User * pUser)
{
	if (NULL == pUser)
	{
		DEBUGLOG("Party::EnterUser NULL == pUser");
		return false;
	}


	auto itr = _clsAllUserTree.find(pUser->GetUserSeq());
	if (itr != _clsAllUserTree.end())
		return false;

	_clsAllUserTree[pUser->GetUserSeq()] = pUser;
	pUser->SetParty(this);

	return true;
}

bool
Party::LeaveUser(User * pUser)
{
	if (NULL == pUser)
	{
		DEBUGLOG("Party::LeaveUser NULL == pUser");
		return false;
	}

	auto itrAll = _clsAllUserTree.find(pUser->GetUserSeq());
	if (itrAll == _clsAllUserTree.end())
		return false;

	_clsAllUserTree.erase(itrAll);
	if (_clsAllUserTree.size() <= 0)
	{
		pUser->SetParty(NULL);
		pUser->SetEnumState(User::EnumState::__NONE__);

		Static::Instance().GETPARTYPOOL()->DEL(this);
		return true;
	}

	// pk 응답 지연 유저에서 삭제 처리
	_pkDelayUserTree.erase(pUser->GetUserSeq());

	bool bRet = false;
	if (this->isMaster(pUser))
	{
		bRet = this->leaveMaster();
	}
	else
	{
		bRet = this->leaveUser(pUser);
	}

	return bRet;
}

User *
Party::FindAllUser(int userseq)
{
	auto itr = _clsAllUserTree.find(userseq);
	if (itr == _clsAllUserTree.end())
		return NULL;

	return itr->second;
}

void
Party::ReadyUserTreeMoveToPlayUserTree()
{
	std::for_each(_clsReadyUserTree.begin(), _clsReadyUserTree.end(), [&](USERTREE::value_type& v) {
		_playUserTree[v.first] = v.second;
		v.second->SetEnumState(User::EnumState::DUNGEON_BATTLE);
	} );

	_clsReadyUserTree.clear();
}
	// 맵이 클리어된 경우 다시 Ready 를 기다리기 위하여 이 처리를 진행 해야 한다.
void
Party::PlayUserTreeMoveToAcceptUserTree()
{
	std::for_each(_playUserTree.begin(), _playUserTree.end(), [&](USERTREE::value_type& v) {
		_clsAcceptUserTree[v.first] = v.second;
		v.second->SetEnumState(User::EnumState::READY_WAIT);
	} );

	_clsReadyUserTree.clear();
	_playUserTree.clear();
	_clsInviteUserTree.clear();
	this->SetState(State::READY_WAIT);
}

Party::USERTREE &
Party::GetAllUserTree()
{
	return _clsAllUserTree;
}

bool
Party::isMaster(User * pUser)
{
	if (NULL == _master)
		return false;

	if (pUser == _master)
		return true;

	return false;
}

bool
Party::leaveMaster()
{
	_master->SetParty(NULL);
	_master->SetEnumState(User::EnumState::__NONE__);

	auto itr = _clsAcceptUserTree.find(_master->GetUserSeq());
	if (itr != _clsAcceptUserTree.end())
		_clsAcceptUserTree.erase(itr);

	itr = _clsReadyUserTree.find(_master->GetUserSeq());
	if (itr != _clsReadyUserTree.end())
		_clsReadyUserTree.erase(itr);

	itr = _playUserTree.find(_master->GetUserSeq());
	if (itr != _playUserTree.end())
		_playUserTree.erase(itr);

	leaveMasterFromDungeon();
	leaveMasterFromPK();
	leaveMasterFromPVP();
	leaveMasterFromNewPartyRoom();
	leaveMasterFromNewPVPRoom();
	leaveMasterFromWorldBoss();

	return true;
}

bool
Party::leaveUser(User * pUser)
{
//	pUser->SetParty(NULL);
//	pUser->SetEnumState(User::EnumState::__NONE__);

	auto itr = _clsInviteUserTree.find(pUser->GetUserSeq());
	if (itr != _clsInviteUserTree.end())
		_clsInviteUserTree.erase(itr);

	itr = _clsAcceptUserTree.find(pUser->GetUserSeq());
	if (itr != _clsAcceptUserTree.end())
		_clsAcceptUserTree.erase(itr);

	itr = _clsReadyUserTree.find(pUser->GetUserSeq());
	if (itr != _clsReadyUserTree.end())
		_clsReadyUserTree.erase(itr);

	itr = _playUserTree.find(pUser->GetUserSeq());
	if (itr != _playUserTree.end())
		_playUserTree.erase(itr);

	leaveUserFromDungeon(pUser);
	leaveUserFromPK(pUser);
	leaveUserFromPVP(pUser);
	leaveUserFromNewPartyRoom(pUser);
	leaveUserFromNewPVPRoom(pUser);
	leaveUserFromWorldBoss(pUser);

	pUser->SetParty(NULL);
	pUser->SetEnumState(User::EnumState::__NONE__);

	return true;
}

void
Party::leaveMasterFromDungeon()
{
	if (NULL == _space)
	{
		PROCESSLOG("%s : _space is NULL!!", __FUNCTION__);
		return;
	}

	if (false == _space->IsPartyDungeon())
	{
		PROCESSLOG("%s : SpaceType is Not Dungeon!! spacetype=%d", __FUNCTION__, _space->GetData()._spaceType);
		return;
	}

	if (true == _space->IsWorldBoss())
	{
		PROCESSLOG("%s : SpaceType is IsWorldBoss spacetype=%d", __FUNCTION__, _space->GetData()._spaceType);
		return;
	}

	if (_space->GetData()._spaceType == Space::SpaceType::NEW_PARTY_ROOM)
	{
		return;
	}

	if (_state == State::INVITE)
	{
		std::for_each(_clsInviteUserTree.begin(), _clsInviteUserTree.end(), [&](const std::pair<int, User *> & pair) {
//			::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
//			* pNoti << static_cast<int16_t>(-1) << static_cast<int8_t>(0);
//			pNoti->MakePacket(CMD_SN_PARTY_CREATE_DONE);
//			pair.second->Send(pNoti);

			pair.second->SetEnumState(User::EnumState::__NONE__);
		} );
	}
	else if (_state == State::ACCEPT_WAIT)
	{
		std::for_each(_clsInviteUserTree.begin(), _clsInviteUserTree.end(), [&](const std::pair<int, User *> & pair) {
			::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
			* pNoti << static_cast<int16_t>(-1) << static_cast<int8_t>(0);
			pNoti->MakePacket(CMD_SN_PARTY_CREATE_DONE);
			pair.second->Send(pNoti);

			pair.second->SetEnumState(User::EnumState::__NONE__);
		} );

		std::vector<User *> clsUserVector;
		std::for_each(_clsAcceptUserTree.begin(), _clsAcceptUserTree.end(), [&](const std::pair<int, User *> & pair) {
			clsUserVector.push_back(pair.second);
		} );

		std::for_each(clsUserVector.begin(), clsUserVector.end(), [&](User * pUser) {
			::Network::Packet * pLeave = ::Network::GETPACKETPOOL()->SEND_NEW();
			pLeave->MsgCat("%d%d", _master->GetUserSeq(), 0);
			pLeave->MakePacket(CMD_SN_PARTY_LEAVE);
			pUser->Send(pLeave);

			::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
			* pNoti << static_cast<int16_t>(-1) << static_cast<int8_t>(0);
			pNoti->MakePacket(CMD_SN_PARTY_CREATE_DONE);
			pUser->Send(pNoti);

			NLogic::Space * pSpace = pUser->GetSpace();
			if (NULL != pSpace)
				pSpace->LeaveUser(pUser);

			pUser->SetEnumState(User::EnumState::__NONE__);

			NLogic::Space * pWorldSpace = pUser->_getWorldSpace();
			if (NULL != pWorldSpace)
				pWorldSpace->EnterUser(pUser);
		} );
		clsUserVector.clear();
	}
	else if (_state == State::READY_WAIT)
	{
		/*
		 * SN_PARTY_LEAVE		0x110e
		{
			u32	leave_gid;
			u32	chief_gid;
		}
		 */

		if (_clsAllUserTree.size() >= 1)
		{
			std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
				::Network::Packet * pLeave = ::Network::GETPACKETPOOL()->SEND_NEW();
				pLeave->MsgCat("%d%d", _master->GetUserSeq(), 0);
				pLeave->MakePacket(CMD_SN_PARTY_LEAVE);
				pair.second->Send(pLeave);
			} );

			int masterSeq = _clsAllUserTree.begin()->second->GetUserSeq();
			User * pReadyMaster = _clsAllUserTree.begin()->second;

			std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
				::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
				pNoti->MsgCat("%d", masterSeq);
				pNoti->MakePacket(CMD_SN_DUNGEON_DELEGATE_CHIEF);
				pair.second->Send(pNoti);
			} );

			if (_clsAcceptUserTree.size() <= 0)
			{
				std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
					::Network::Packet * pNoti2 = ::Network::GETPACKETPOOL()->SEND_NEW();
					pNoti2->MakePacket(CMD_SN_PARTY_START);
					pair.second->Send(pNoti2);

					pair.second->SetEnumState(User::EnumState::DUNGEON_BATTLE);
					this->SetState(State::DUNGEON_BATTLE);
				} );
			}

			// 마스터 위임
			_isChangeMaster = true;
			_master = pReadyMaster;
		}
	}
	else if (_state == State::DUNGEON_BATTLE)
	{
		/*
		 * SN_PARTY_LEAVE		0x110e
		{
			u32	leave_gid;
			u32	chief_gid;
		}
		 */

		if (_playUserTree.size() >= 1)
		{
			int masterSeq = _playUserTree.begin()->second->GetUserSeq();
			std::for_each(_playUserTree.begin(), _playUserTree.end(), [&](const std::pair<int, User *> & pair) {
				DEBUGLOG("CMD_SN_PARTY_LEAVE");
				::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
				pNoti->MsgCat("%d%d", _master->GetUserSeq(), masterSeq);
				pNoti->MakePacket(CMD_SN_PARTY_LEAVE);
				pair.second->Send(pNoti);
			} );

			_master = _playUserTree.begin()->second;
		}
	}
}

void
Party::leaveUserFromDungeon(User * pUser)
{
	if (NULL == _space)
	{
		PROCESSLOG("%s : _space is NULL!!", __FUNCTION__);
		return;
	}

	if (false == _space->IsPartyDungeon())
	{
		PROCESSLOG("%s : SpaceType is Not Dungeon!! spacetype=%d", __FUNCTION__, _space->GetData()._spaceType);
		return;
	}

	if (true == _space->IsWorldBoss())
	{
		PROCESSLOG("%s : SpaceType is IsWorldBoss spacetype=%d", __FUNCTION__, _space->GetData()._spaceType);
		return;
	}

	if (_space->GetData()._spaceType == Space::SpaceType::NEW_PARTY_ROOM)
	{
		return;
	}

	if (_state == State::ACCEPT_WAIT)
	{
		if (pUser->GetEnumState() == User::EnumState::READY_WAIT)
		{
			::Network::Packet * pLeave = ::Network::GETPACKETPOOL()->SEND_NEW();
			pLeave->MsgCat("%d%d", pUser->GetUserSeq(), 0);
			pLeave->MakePacket(CMD_SN_PARTY_LEAVE);
			_master->Send(pLeave);

			std::for_each(_clsAcceptUserTree.begin(), _clsAcceptUserTree.end(), [&](const std::pair<int, User *> & pair) {
				::Network::Packet * pLeave = ::Network::GETPACKETPOOL()->SEND_NEW();
				pLeave->MsgCat("%d%d", pUser->GetUserSeq(), 0);
				pLeave->MakePacket(CMD_SN_PARTY_LEAVE);
				pair.second->Send(pLeave);
			} );
		}

		// 초대를 받은 유저가 모두 나간 경우....
		if (_clsInviteUserTree.size() <= 0)
		{
			std::for_each(_clsAcceptUserTree.begin(), _clsAcceptUserTree.end(), [&](const std::pair<int, User *> & pair) {
				::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
				* pNoti << static_cast<int16_t>(ACK_OK) << static_cast<int8_t>(0);
				pNoti->MakePacket(CMD_SN_PARTY_CREATE_DONE);
				pair.second->Send(pNoti);
				pair.second->SetEnumState(User::EnumState::READY_WAIT);
			} );

			this->SetState(State::READY_WAIT);
		}
	}
	else if (_state == State::READY_WAIT && pUser->GetEnumState() == User::EnumState::READY_WAIT)
	{
		::Network::Packet * pLeave = ::Network::GETPACKETPOOL()->SEND_NEW();
		pLeave->MsgCat("%d%d", pUser->GetUserSeq(), 0);
		pLeave->MakePacket(CMD_SN_PARTY_LEAVE);
		_master->Send(pLeave);

		if (_clsReadyUserTree.size() <= 0)
		{
			::Network::Packet * pNoti2 = ::Network::GETPACKETPOOL()->SEND_NEW();
			pNoti2->MakePacket(CMD_SN_PARTY_START);
			_master->Send(pNoti2);

			_master->SetEnumState(User::EnumState::DUNGEON_BATTLE);
			this->SetState(State::DUNGEON_BATTLE);
		}
		else
		{
			std::for_each(_clsReadyUserTree.begin(), _clsReadyUserTree.end(), [&](const std::pair<int, User *> & pair) {
				::Network::Packet * pLeave = ::Network::GETPACKETPOOL()->SEND_NEW();
				pLeave->MsgCat("%d%d", pUser->GetUserSeq(), 0);
				pLeave->MakePacket(CMD_SN_PARTY_LEAVE);
				pair.second->Send(pLeave);
			} );
		}
	}
	else if (_state == State::DUNGEON_BATTLE && pUser->GetEnumState() == User::EnumState::DUNGEON_BATTLE)
	{
		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
			::Network::Packet * pLeave = ::Network::GETPACKETPOOL()->SEND_NEW();
			pLeave->MsgCat("%d%d", pUser->GetUserSeq(), 0);
			pLeave->MakePacket(CMD_SN_PARTY_LEAVE);
			pair.second->Send(pLeave);

			DEBUGLOG("CMD_SN_PARTY_LEAVE FROM GID : %d TO GID : %d", pUser->GetUserSeq(), pair.second->GetUserSeq());
		} );
	}
}

void
Party::leaveMasterFromPK()
{
	if (NULL == _space)
	{
		PROCESSLOG("%s : _space is NULL!!", __FUNCTION__);
		return;
	}

	if (_space->GetData()._spaceType != Space::SpaceType::BATTLEROYAL)
	{
		PROCESSLOG("%s : SpaceType is Not PK!! spacetype=%d", __FUNCTION__, _space->GetData()._spaceType);
		return;
	}

	if (_state == NLogic::Party::State::NEW_PK_ROOM_WAIT)
	{
		::Dispatcher::GETTIMER()->KillTimer(this);
		onTime_PK_CANCEL();
	}
}

void
Party::leaveUserFromPK(User * pUser)
{
	if (NULL == _space)
	{
		PROCESSLOG("%s : _space is NULL!!", __FUNCTION__);
		return;
	}

	if (_space->GetData()._spaceType != Space::SpaceType::BATTLEROYAL)
	{
		PROCESSLOG("%s : SpaceType is Not PK!! spacetype=%d", __FUNCTION__, _space->GetData()._spaceType);
		return;
	}
}

void
Party::leaveMasterFromPVP()
{
	if (NULL == _space)
	{
		PROCESSLOG("%s : _space is NULL!!", __FUNCTION__);
		return;
	}

	if (_space->GetData()._spaceType != Space::SpaceType::PVP_USER)
	{
		PROCESSLOG("%s : SpaceType is Not PVP_USER!! spacetype=%d", __FUNCTION__, _space->GetData()._spaceType);
		return;
	}

	if (_state == State::PVP_ACCEPT_WAIT)
	{
		_master = NULL;
	}
}

void
Party::leaveUserFromPVP(User * pUser)
{
	if (NULL == _space)
	{
		PROCESSLOG("%s : _space is NULL!!", __FUNCTION__);
		return;
	}

	if (_space->GetData()._spaceType != Space::SpaceType::PVP_USER)
	{
		PROCESSLOG("%s : SpaceType is Not PVP_USER!! spacetype=%d", __FUNCTION__, _space->GetData()._spaceType);
		return;
	}
}

void
Party::leaveMasterFromNewPVPRoom()
{
	if (NULL == _space)
	{
		PROCESSLOG("%s : _space is NULL!!", __FUNCTION__);
		return;
	}

	if (_space->GetData()._spaceType != Space::SpaceType::NEW_PVP_ROOM)
	{
		PROCESSLOG("%s : SpaceType is Not ROOM_PVP!! spacetype=%d", __FUNCTION__, _space->GetData()._spaceType);
		return;
	}

	if (_state == State::NEW_PVP_ROOM_ACCEPT_WAIT)
	{
		_master = NULL;
	}
}

void
Party::leaveUserFromNewPVPRoom(User * pUser)
{
	if (NULL == _space)
	{
		PROCESSLOG("%s : _space is NULL!!", __FUNCTION__);
		return;
	}

	if (_space->GetData()._spaceType != Space::SpaceType::NEW_PVP_ROOM)
	{
		PROCESSLOG("%s : SpaceType is Not ROOM_PVP!! spacetype=%d", __FUNCTION__, _space->GetData()._spaceType);
		return;
	}
}

void
Party::leaveMasterFromWorldBoss()
{
	if (NULL == _space)
	{
		PROCESSLOG("%s : _space is NULL!!", __FUNCTION__);
		return;
	}

	if (false == _space->IsWorldBoss())
	{
		PROCESSLOG("%s : SpaceType is Not IsWorldBoss!! spacetype=%d", __FUNCTION__, _space->GetData()._spaceType);
		return;
	}

	// 방장이 기다리던중 그냥 나간경우... 방폭...
	if (_state == State::WORLD_BOSS_WAIT && _state == State::WORLD_BOSS_WAIT_FRIEND)
	{
		std::vector<User *> clsUserVector;

		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](USERTREE::value_type & pair) {
			User * pUser = pair.second;
			clsUserVector.push_back(pUser);
		} );

		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
		* pNoti << static_cast<int16_t>(ACK_OK);
		pNoti->MakePacket(CMD_SN_DUNGEON_PARTY_CANCLE);
		std::for_each(clsUserVector.begin(), clsUserVector.end(), [&](User * pUser) {
			pUser->SendOneshotEncrypt(pNoti);

			NLogic::Space * pSpace = pUser->GetSpace();
			if (NULL != pSpace)
				pSpace->LeaveUser(pUser);
		} );
		::Network::GETPACKETPOOL()->SEND_DEL(pNoti);
		clsUserVector.clear();
	}
	else if (_state == State::READY_WAIT)
	{
		/*
		 * SN_PARTY_LEAVE		0x110e
		{
			u32	leave_gid;
			u32	chief_gid;
		}
		 */

		if (_clsAllUserTree.size() >= 1)
		{
			std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
				::Network::Packet * pLeave = ::Network::GETPACKETPOOL()->SEND_NEW();
				pLeave->MsgCat("%d%d", _master->GetUserSeq(), 0);
				pLeave->MakePacket(CMD_SN_PARTY_LEAVE);
				pair.second->Send(pLeave);
			} );

			int masterSeq = _clsAllUserTree.begin()->second->GetUserSeq();
			User * pReadyMaster = _clsAllUserTree.begin()->second;

			std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
				::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
				pNoti->MsgCat("%d", masterSeq);
				pNoti->MakePacket(CMD_SN_DUNGEON_DELEGATE_CHIEF);
				pair.second->Send(pNoti);
			} );

			if (_clsAcceptUserTree.size() <= 0)
			{
				std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
					::Network::Packet * pNoti2 = ::Network::GETPACKETPOOL()->SEND_NEW();
					pNoti2->MakePacket(CMD_SN_PARTY_START);
					pair.second->Send(pNoti2);

					pair.second->SetEnumState(User::EnumState::DUNGEON_BATTLE);
					this->SetState(State::DUNGEON_BATTLE);
				} );
			}

			// 마스터 위임
			_isChangeMaster = true;
			_master = pReadyMaster;
		}
	}
	else if (_state == State::DUNGEON_BATTLE)
	{
		/*
		 * SN_PARTY_LEAVE		0x110e
		{
			u32	leave_gid;
			u32	chief_gid;
		}
		 */

		if (_playUserTree.size() >= 1)
		{
			int masterSeq = _playUserTree.begin()->second->GetUserSeq();
			std::for_each(_playUserTree.begin(), _playUserTree.end(), [&](const std::pair<int, User *> & pair) {
				DEBUGLOG("CMD_SN_PARTY_LEAVE");
				::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
				pNoti->MsgCat("%d%d", _master->GetUserSeq(), masterSeq);
				pNoti->MakePacket(CMD_SN_PARTY_LEAVE);
				pair.second->Send(pNoti);
			} );

			_master = _playUserTree.begin()->second;
		}
	}
}

void
Party::leaveUserFromWorldBoss(User * pUser)
{
	if (NULL == _space)
	{
		PROCESSLOG("%s : _space is NULL!!", __FUNCTION__);
		return;
	}

	if (false == _space->IsWorldBoss())
	{
		PROCESSLOG("%s : _space is Not IsWorldBoss!!", __FUNCTION__);
		return;
	}

	if (_state == State::WORLD_BOSS_WAIT || _state == State::WORLD_BOSS_WAIT_FRIEND)
	{
		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
		* pNoti << pUser->GetUserSeq();
		pNoti->MakePacket(CMD_SN_WORLD_BOSS_PARTY_MEMBER_LEAVE);

		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
			User * pUser = pair.second;

			pUser->SendOneshotEncrypt(pNoti);
		} );
		::Network::GETPACKETPOOL()->SEND_DEL(pNoti);
	}
	else
	{
		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
		* pNoti << pUser->GetUserSeq() << static_cast<uint32_t>(0);
		pNoti->MakePacket(CMD_SN_PARTY_LEAVE);

		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
			User * pUser = pair.second;

			pUser->SendOneshotEncrypt(pNoti);
		} );
		::Network::GETPACKETPOOL()->SEND_DEL(pNoti);
	}
}

void
Party::leaveMasterFromNewPartyRoom()
{
	if (NULL == _space)
	{
		PROCESSLOG("%s : _space is NULL!!", __FUNCTION__);
		return;
	}

	if (_space->GetData()._spaceType != Space::SpaceType::NEW_PARTY_ROOM)
	{
		return;
	}

	// 방장이 기다리던중 그냥 나간경우... 방폭...
	if (_state == State::NEW_PARTY_ROOM_WAIT)
	{
		std::vector<User *> clsUserVector;

		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](USERTREE::value_type & pair) {
			User * pUser = pair.second;
			clsUserVector.push_back(pUser);
		} );

		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
		* pNoti << static_cast<int16_t>(ACK_OK);
		pNoti->MakePacket(CMD_SN_DUNGEON_PARTY_CANCLE);
		std::for_each(clsUserVector.begin(), clsUserVector.end(), [&](User * pUser) {
			pUser->SendOneshotEncrypt(pNoti);

			NLogic::Space * pSpace = pUser->GetSpace();
			if (NULL != pSpace)
				pSpace->LeaveUser(pUser);
		} );
		::Network::GETPACKETPOOL()->SEND_DEL(pNoti);
		clsUserVector.clear();
	}
	else if (_state == State::READY_WAIT)
	{
		/*
		 * SN_PARTY_LEAVE		0x110e
		{
			u32	leave_gid;
			u32	chief_gid;
		}
		 */

		if (_clsAllUserTree.size() >= 1)
		{
			std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
				::Network::Packet * pLeave = ::Network::GETPACKETPOOL()->SEND_NEW();
				pLeave->MsgCat("%d%d", _master->GetUserSeq(), 0);
				pLeave->MakePacket(CMD_SN_PARTY_LEAVE);
				pair.second->Send(pLeave);
			} );

			int masterSeq = _clsAllUserTree.begin()->second->GetUserSeq();
			User * pReadyMaster = _clsAllUserTree.begin()->second;

			std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
				::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
				pNoti->MsgCat("%d", masterSeq);
				pNoti->MakePacket(CMD_SN_DUNGEON_DELEGATE_CHIEF);
				pair.second->Send(pNoti);
			} );

			if (_clsAcceptUserTree.size() <= 0)
			{
				std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
					::Network::Packet * pNoti2 = ::Network::GETPACKETPOOL()->SEND_NEW();
					pNoti2->MakePacket(CMD_SN_PARTY_START);
					pair.second->Send(pNoti2);

					pair.second->SetEnumState(User::EnumState::DUNGEON_BATTLE);
					this->SetState(State::DUNGEON_BATTLE);
				} );
			}

			// 마스터 위임
			_isChangeMaster = true;
			_master = pReadyMaster;
		}
	}
	else if (_state == State::DUNGEON_BATTLE)
	{
		/*
		 * SN_PARTY_LEAVE		0x110e
		{
			u32	leave_gid;
			u32	chief_gid;
		}
		 */

		if (_playUserTree.size() >= 1)
		{
			int masterSeq = _playUserTree.begin()->second->GetUserSeq();
			std::for_each(_playUserTree.begin(), _playUserTree.end(), [&](const std::pair<int, User *> & pair) {
				DEBUGLOG("CMD_SN_PARTY_LEAVE");
				::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
				pNoti->MsgCat("%d%d", _master->GetUserSeq(), masterSeq);
				pNoti->MakePacket(CMD_SN_PARTY_LEAVE);
				pair.second->Send(pNoti);
			} );

			_master = _playUserTree.begin()->second;
		}
	}
}

void
Party::leaveUserFromNewPartyRoom(User * pUser)
{
	if (NULL == _space)
	{
		PROCESSLOG("%s : _space is NULL!!", __FUNCTION__);
		return;
	}

	if (_space->GetData()._spaceType != Space::SpaceType::NEW_PARTY_ROOM)
	{
		return;
	}

	if (_state == State::NEW_PARTY_ROOM_WAIT)
	{
		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
		* pNoti << pUser->GetUserSeq();
		pNoti->MakePacket(CMD_SN_DUNGEON_PARTY_MEMBER_LEAVE);

		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
			User * pUser = pair.second;

			pUser->SendOneshotEncrypt(pNoti);
		} );
		::Network::GETPACKETPOOL()->SEND_DEL(pNoti);
	}
	else
	{
		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
		* pNoti << pUser->GetUserSeq() << static_cast<uint32_t>(0);
		pNoti->MakePacket(CMD_SN_PARTY_LEAVE);

		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
			User * pUser = pair.second;

			pUser->SendOneshotEncrypt(pNoti);
		} );
		::Network::GETPACKETPOOL()->SEND_DEL(pNoti);
	}
}


bool
Party::AddInviteUserTree(User * pUser)
{
	auto itr = _clsInviteUserTree.find(pUser->GetUserSeq());
	if (itr != _clsInviteUserTree.end())
		return false;

	_clsInviteUserTree[pUser->GetUserSeq()] = pUser;
	return true;
}

bool
Party::AddAcceptUserTree(User * pUser)
{
	auto itr = _clsInviteUserTree.find(pUser->GetUserSeq());
	if (itr != _clsInviteUserTree.end())
		_clsInviteUserTree.erase(itr);

	itr = _clsAcceptUserTree.find(pUser->GetUserSeq());
	if (itr != _clsAcceptUserTree.end())
		return false;

	_clsAcceptUserTree[pUser->GetUserSeq()] = pUser;
	return true;
}

bool
Party::AddReadyUserTree(User * pUser)
{
	auto itr = _clsReadyUserTree.find(pUser->GetUserSeq());
	if (itr != _clsReadyUserTree.end())
		return false;

	_clsReadyUserTree[pUser->GetUserSeq()] = pUser;
	return true;
}

bool
Party::AddPlayUserTree(User * pUser)
{
	auto itr = _clsReadyUserTree.find(pUser->GetUserSeq());
	if (itr != _clsReadyUserTree.end())
		_clsReadyUserTree.erase(itr);

	itr = _playUserTree.find(pUser->GetUserSeq());
	if (itr != _playUserTree.end())
		return false;

	_playUserTree[pUser->GetUserSeq()] = pUser;
	return true;
}

void
Party::SetState(State eState)
{
	_state = eState;

	// SC_PARTY_INVITE => CN_PARTY_INVITE_RES( 12초 동안 응답없으면 timeout) => 취소
	if (_state == State::ACCEPT_WAIT)
	{
		this->setTimer(1000 * 12, static_cast<int>(State::ACCEPT_WAIT));
	}

	// SN_PARTY_CREATE_DONE  => CS_PARTY_READY(10초 동안 응답없으면 timeout) => 계속 진행
	if (_state == State::READY_WAIT)
	{
		this->killTimer(static_cast<int>(State::ACCEPT_WAIT));
		this->killTimer(static_cast<int>(State::DUNGEON_BATTLE));
		this->killTimer(static_cast<int>(State::NEW_PARTY_ROOM_WAIT));
		this->killTimer(static_cast<int>(State::WORLD_BOSS_WAIT));
		this->killTimer(static_cast<int>(State::WORLD_BOSS_WAIT_FRIEND));

		this->setTimer(1000 * 15, static_cast<int>(State::READY_WAIT));
	}

	if (_state == State::DUNGEON_BATTLE)
	{
		this->killTimer(static_cast<int>(State::READY_WAIT));
		this->setTimer(1000, static_cast<int>(State::DUNGEON_BATTLE));
	}

	if (_state == State::DUNGEON_CLEAR)
	{
		this->killTimer(static_cast<int>(State::DUNGEON_BATTLE));
		this->setTimer(1000 * 10, static_cast<int>(State::DUNGEON_CLEAR));
	}


	if (_state == State::PVP_ACCEPT_WAIT)
	{
		this->setTimer(1000 * 10, static_cast<int>(State::PVP_ACCEPT_WAIT));
	}

	if (_state == State::PVP_ENTERROOM_WAIT)
	{
		this->killTimer(static_cast<int>(State::PVP_ACCEPT_WAIT));
		this->killTimer(static_cast<int>(State::NEW_PVP_ROOM_ACCEPT_WAIT));
		this->setTimer(1000 * 15, static_cast<int>(State::PVP_ENTERROOM_WAIT));
	}

	if (_state == State::PVP_READY_WAIT)
	{
		this->killTimer(static_cast<int>(State::PVP_ENTERROOM_WAIT));
		this->setTimer(1000 * 10, static_cast<int>(State::PVP_READY_WAIT));
	}

	if (_state == State::PVP_BATTLE)
	{
		if (NULL == _space)
		{
			this->killTimer(static_cast<int>(State::PVP_READY_WAIT));
			this->setTimer(1000, static_cast<int>(State::PVP_BATTLE));
			return;
		}

		time_t curtime = time(NULL);
		std::for_each(this->GetAllUserTree().begin(), this->GetAllUserTree().end(), [&](NLogic::Party::USERTREE::value_type & pair){
			User * pUser = pair.second;
			NLogic::Battle * pBattle = pUser->GetBattle();

			::ProjectZ::NGameLog::Bson * pBson = ::ProjectZ::NGameLog::Static::Instance().GETBSONPOOL()->NEW();

			if(NULL != pBson && NULL != pBattle)
			{
				User * pFighter = pBattle->GetData()._pvpOppUser;

				if (NULL != pFighter)
				{
					pBson->SetCollections("log_pvp_play");

					bson * bson = pBson->GetBsonData();
					bson_append_int( bson, "user_seq", pUser->GetUserSeq() );
					bson_append_int( bson, "company", pUser->GetCompany() );
					bson_append_int( bson, "sale_code", pUser->GetSaleCode() );
					bson_append_int( bson, "character_class", pUser->GetCharacterInfo().classtype );
					bson_append_int( bson, "character_level", pUser->GetCharacterInfo().level );

					bson_append_int( bson, "enermy_user_seq", pFighter->GetUserSeq() );
					bson_append_int( bson, "enermy_company", pFighter->GetCompany() );
					bson_append_int( bson, "enermy_sale_code", pFighter->GetSaleCode() );
					bson_append_int( bson, "enermy_character_class", pFighter->GetCharacterInfo().classtype );
					bson_append_int( bson, "enermy_character_level", pFighter->GetCharacterInfo().level );

					bson_append_int( bson, "space_num", _space->GetData()._index );
					bson_append_time_t( bson, "start_time", curtime );
					bson_append_int( bson, "end_time", 0 );
					bson_append_int( bson, "play_time", 0 );
					bson_append_int( bson, "item_seq", 0 );
					bson_append_int( bson, "win_point", 0 );
					bson_append_time_t( bson, "reg_time", curtime );

					::ProjectZ::NGameLog::MongoDB * pMongoDB = ::ProjectZ::NGameLog::Static::Instance().GetMongoDB();
					pMongoDB->Push(pBson);
				}
			}
		});

		_space->GetData()._starttick = curtime;

		this->killTimer(static_cast<int>(State::PVP_READY_WAIT));
		this->setTimer(1000, static_cast<int>(State::PVP_BATTLE));
	}

	if (_state == State::PVP_BATTLE_END)
	{
		this->killTimer(static_cast<int>(State::PVP_BATTLE));
	}

	if (_state == State::PK_ACCEPT_WAIT)
	{
		this->setTimer(1000 * 10, static_cast<int>(State::PK_ACCEPT_WAIT));
	}

	if (_state == State::PK_ENTER_WAIT)
	{
		::Dispatcher::GETTIMER()->KillTimer(this);
		this->setTimer(1000 * 15, static_cast<int>(State::PK_ENTER_WAIT));
	}

	if (_state == State::PK_READY_WAIT)
	{
		this->killTimer(static_cast<int>(State::PK_ENTER_WAIT));
		this->setTimer(1000 * 10, static_cast<int>(State::PK_READY_WAIT));
	}

	if (_state == State::PK_BATTLE)
	{
		this->killTimer(static_cast<int>(State::PK_READY_WAIT));
		this->setTimer(1000, static_cast<int>(State::PK_BATTLE));
	}

	if (_state == State::PK_END)
	{
		::Dispatcher::GETTIMER()->KillTimer(this);
	}

	if (_state == State::PK_CANCEL)
	{
		::Dispatcher::GETTIMER()->KillTimer(this);
		this->onTime_PK_CANCEL();
	}

	if (_state == State::NEW_PARTY_ROOM_WAIT)
	{
		// 1분 타이머 가동...
		this->setTimer(1000 * 60, static_cast<int>(State::NEW_PARTY_ROOM_WAIT));
		SetRoomWaitEndTime(time(NULL) + 60);
	}

	if (_state == State::NEW_PK_ROOM_WAIT)
	{
		// 1분 타이머 가동...
		this->setTimer(1000 * 60, static_cast<int>(State::NEW_PK_ROOM_WAIT));
		SetRoomWaitEndTime(time(NULL) + 60);
	}
	
	if (_state == State::NEW_PVP_ROOM_ACCEPT_WAIT)
	{
		// 1분 타이머 가동...
		this->setTimer(1000 * 60, static_cast<int>(State::NEW_PVP_ROOM_ACCEPT_WAIT));
	}

	if (_state == State::WORLD_BOSS_WAIT)
	{
		DEBUGLOG("%s _state == State::WORLD_BOSS_WAIT", __FUNCTION__);
		// 1분 타이머 가동...
		this->setTimer(1000 * 60, static_cast<int>(State::WORLD_BOSS_WAIT));
		SetRoomWaitEndTime(time(NULL) + 60);
	}

	if (_state == State::WORLD_BOSS_WAIT_FRIEND)
	{
		DEBUGLOG("%s _state == State::WORLD_BOSS_WAIT_FRIEND", __FUNCTION__);
		// 1분 타이머 가동...
		this->setTimer(1000 * 10, static_cast<int>(State::WORLD_BOSS_WAIT_FRIEND));
	}

}

void
Party::SetTimer(uint32_t millisec, TimerID id)
{
	_interval = millisec;
	::Dispatcher::Timer::Argument clsArgument(millisec, static_cast<int>(id), NULL, this);
	::Dispatcher::GETTIMER()->SetTimer(clsArgument);
}

bool
Party::OnTime(int id, void* param)
{
	bool bRet = false;
	switch(id)
	{
	case static_cast<int>(State::ACCEPT_WAIT):
		bRet = this->onTime_ACCEPT_WAIT();
		break;
	case static_cast<int>(State::READY_WAIT):
		bRet = this->onTime_READY_WAIT();
		break;
	case static_cast<int>(State::DUNGEON_BATTLE):
		bRet = this->onTime_DUNGEON_BATTLE();
		break;
	case static_cast<int>(State::DUNGEON_CLEAR):
		bRet = this->onTime_DUNGEON_CLEAR();
		break;
	case static_cast<int>(State::PVP_ACCEPT_WAIT):
		bRet = this->onTime_PVP_ACCEPT_WAIT();
		break;
	case static_cast<int>(State::PVP_ENTERROOM_WAIT):
		bRet = this->onTime_PVP_ENTERROOM_WAIT();
		break;
	case static_cast<int>(State::PVP_READY_WAIT):
		bRet = this->onTime_PVP_READY_WAIT();
		break;
	case static_cast<int>(State::PVP_BATTLE):
		bRet = this->onTime_PVP_BATTLE();
		break;
	case static_cast<int>(State::PK_ACCEPT_WAIT):
		bRet = this->onTime_PK_ACCEPT_WAIT();
		break;
	case static_cast<int>(State::PK_ENTER_WAIT):
		bRet = this->onTime_PK_CANCEL();
		break;
	case static_cast<int>(State::PK_READY_WAIT):
		bRet = this->onTime_PK_READY_WAIT();
		break;
	case static_cast<int>(State::PK_BATTLE):
		bRet = this->onTime_PK_BATTLE();
		break;
	case static_cast<int>(State::NEW_PARTY_ROOM_WAIT):
		bRet = this->onTime_New_Party_Room();
		break;
	case static_cast<int>(State::NEW_PK_ROOM_WAIT):
		bRet = this->onTime_PK_CANCEL();
		break;
	case static_cast<int>(State::NEW_PVP_ROOM_ACCEPT_WAIT):
		bRet = this->onTime_NEW_PVP_ROOM_WAIT();
		break;
	case static_cast<int>(State::WORLD_BOSS_WAIT):
		bRet = this->onTime_WORLDBOSS_WAIT();
		break;
	case static_cast<int>(State::WORLD_BOSS_WAIT_FRIEND):
		bRet = this->onTime_WORLDBOSS_WAIT_FRIEND();
		break;
	case static_cast<int>(State::HEAL_BUFF):
		bRet = this->onTime_HEAL_BUFF();
		break;
	default:
		break;
	}
	return bRet;
}

void
Party::EndPVPBattle()
{
	// 여긴 ai 로 붙은 유저....
	if (NULL != _pvpDelayUser)
		_pvpDelayUser->SetPVPBattleResult_afterEffect();
}

void
Party::EndPKBattle()
{
	// 여긴 ai 로 붙은 유저....
	std::for_each(_pkDelayUserTree.begin(), _pkDelayUserTree.end(), [](USERTREE::value_type & pair) {
		pair.second->SetPKBattleResult_afterEffect();
	} );
}

void
Party::setTimer(unsigned int interval, int timerID)
{
	DEBUGLOG("PARTYTIMER SET timerID : %d", timerID);
	::Dispatcher::Timer::Argument clsArgument(interval, timerID, NULL, this);
	::Dispatcher::GETTIMER()->SetTimer(clsArgument);
}

void
Party::killTimer(int timerID)
{
	DEBUGLOG("PARTYTIMER KILL timerID : %d", timerID);
	::Dispatcher::GETTIMER()->KillTimer(this, timerID);
}

bool
Party::onTime_ACCEPT_WAIT()
{
	DEBUGLOG("onTime_ACCEPT_WAIT");

	std::vector<User*> vec;
	std::for_each(_clsInviteUserTree.begin(), _clsInviteUserTree.end(), [&](const std::pair<int, User *> & pair) {
		vec.push_back(pair.second);
	} );

	auto it = vec.begin();
	for(; it != vec.end(); ++it)
	{
		User * pUser = (*it);
		NLogic::Party * pParty = pUser->GetParty();
		if (NULL != pParty)
			pParty->LeaveUser(pUser);
	}
	vec.clear();

	// 유저들이 던전을 진행할 수 있도록 처리..
	std::for_each(_clsAcceptUserTree.begin(), _clsAcceptUserTree.end(), [&](const std::pair<int, User *> & pair) {
		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
		* pNoti << static_cast<int16_t>(1) << static_cast<int8_t>(0);
		pNoti->MakePacket(CMD_SN_PARTY_CREATE_DONE);
		pair.second->Send(pNoti);
		pair.second->SetEnumState(User::EnumState::READY_WAIT);
	} );

	this->SetState(State::READY_WAIT);
	return false;
}

bool
Party::onTime_READY_WAIT()
{
	DEBUGLOG("onTime_READY_WAIT");

	if (false == checkTimeout())
		return true;

	// Accept 한 유저들만 존재하는 경우....
	// 모든 유저를 던전 밖으로 내보낸다...
	if (_clsReadyUserTree.size() <= 0)
	{
		std::vector<User*> vec;
		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](USERTREE::value_type& pair) {
			vec.push_back(pair.second);
		} );

		auto it = vec.begin();
		for(; it != vec.end(); ++it)
		{
			if (NULL != (*it)->GetSpace())
				(*it)->GetSpace()->LeaveUser(*it);
		}
		vec.clear();
		return false;
	}

	// 마스터가 응답이 없는 경우.... 마스터를 변경....
	auto itr = _clsAcceptUserTree.find(_master->GetUserSeq());
	if (itr != _clsAcceptUserTree.end())
	{
		User * pReadyMaster = _clsReadyUserTree.begin()->second;
		int masterSeq = pReadyMaster->GetUserSeq();

		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](USERTREE::value_type& pair) {
				::Network::Packet * pNotiChangeChief = ::Network::GETPACKETPOOL()->SEND_NEW();
				pNotiChangeChief->MsgCat("%d", masterSeq);
				pNotiChangeChief->MakePacket(CMD_SN_DUNGEON_DELEGATE_CHIEF);
				pair.second->Send(pNotiChangeChief);
		});

		_isChangeMaster = true;
		_master = pReadyMaster;
	}

	std::vector<User*> vec;
	std::for_each(_clsAcceptUserTree.begin(), _clsAcceptUserTree.end(), [&](USERTREE::value_type& v) {

		// 레디 하지 않는 유저들은 파티 리브 발송.
		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](USERTREE::value_type& pair) {
			::Network::Packet * pLeave = ::Network::GETPACKETPOOL()->SEND_NEW();
			pLeave->MsgCat("%d%d", v.second->GetUserSeq(), 0);
			pLeave->MakePacket(CMD_SN_PARTY_LEAVE);
			pair.second->Send(pLeave);
		});

		vec.push_back(v.second);
	} );

	// 던전에서 내보내기....
	auto it = vec.begin();
	for(; it != vec.end(); ++it)
	{
		(*it)->SetBattle_afterEffect();
		if (NULL != (*it)->GetSpace())
			(*it)->GetSpace()->LeaveUser(*it);
	}
	_clsAcceptUserTree.clear();
	vec.clear();


	// 이미 래디를 진행한 유저 들에게는 시작을 알린다....
	std::for_each(_clsReadyUserTree.begin(), _clsReadyUserTree.end(), [&](USERTREE::value_type& pair) {
		_playUserTree[pair.first] = pair.second;
		pair.second->SetEnumState(User::EnumState::DUNGEON_BATTLE);

		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
		pNoti->MakePacket(CMD_SN_PARTY_START);
		pair.second->Send(pNoti);
	} );

	this->SetState(State::DUNGEON_BATTLE);

	if (true == _space->GetData()._isFirstStart)
	{
		//				pSpace->GetData()._starttick = NF::GetTickCount();
		_space->GetData()._starttick = time(NULL);
		_space->GetData()._isFirstStart = false;

		std::for_each(this->GetAllUserTree().begin(), this->GetAllUserTree().end(), [&](NLogic::Party::USERTREE::value_type & pair){
			User * pUser = pair.second;
			::ProjectZ::NGameLog::Bson * pBson = ::ProjectZ::NGameLog::Static::Instance().GETBSONPOOL()->NEW();
			if(NULL != pBson)
			{
				pBson->SetCollections("log_dungeon_play");
				bson * bson = pBson->GetBsonData();
				bson_append_int( bson, "user_seq", pUser->GetUserSeq() );
				bson_append_int( bson, "company", pUser->GetCompany() );
				bson_append_int( bson, "sale_code", pUser->GetSaleCode() );
				bson_append_int( bson, "character_class", pUser->GetCharacterInfo().classtype );
				bson_append_int( bson, "character_level", pUser->GetCharacterInfo().level );
				bson_append_int( bson, "space_num", _space->GetData()._index );
				bson_append_int( bson, "start_time", _space->GetData()._starttick );
				bson_append_int( bson, "end_time", _space->GetData()._finishtick );
				bson_append_int( bson, "play_time", 0 );
				bson_append_int( bson, "dungeon_type", static_cast<int>(_space->GetData()._spaceType) );
				bson_append_int( bson, "dungeon_tid", _space->GetData()._table_id );
				bson_append_int( bson, "dungeon_mod", _space->GetData()._difficulty );
				bson_append_int( bson, "exp", pUser->GetBattle()->GetData().hunting_exp );
				bson_append_int( bson, "gold", pUser->GetBattle()->GetData().get_gold );
				bson_append_int( bson, "item_seq", 0 );
				bson_append_time_t( bson, "reg_time", time(NULL) );

				::ProjectZ::NGameLog::MongoDB * pMongoDB = ::ProjectZ::NGameLog::Static::Instance().GetMongoDB();
				pMongoDB->Push(pBson);
			}
		});
	}



	return false;
}

bool
Party::onTime_DUNGEON_BATTLE()
{
	DEBUGLOG("onTime_DUNGEON_BATTLE");

	if (false == checkTimeout())
		return true;

	this->onTime_DUNGEON_BATTLE_CheckPlayer();

	if (NULL == _master)
	{
		DEBUGLOG("onTime_DUNGEON_BATTLE NULL == _master");
		return false;
	}

	// 3초 이내에 응답을 한 경우는 스킵.....
	if (ProjectZ::NLogic::NFunction::GetTickCount() - _master->GetLastLatency() < 3 * 1000)
	{
		return true;
	}

	// 마스터가 3초간 응답이 없는 경우...
	if (_playUserTree.size() < 1)
	{
		DEBUGLOG("onTime_DUNGEON_BATTLE _playUserTree.size() < 1");
		return false;
	}

	int masterSeq = 0;
	User * pReadyMaster = NULL;
	std::for_each(_playUserTree.begin(), _playUserTree.end(), [&](const std::pair<int, User *> & pair) {

		// 마스터가 아니면서 3초 이내에 응답이 있던 유저를 선별한다....
		if (_master != pair.second && ProjectZ::NLogic::NFunction::GetTickCount() - pair.second->GetLastLatency() < 3 * 1000)
		{
			masterSeq = pair.first;
			pReadyMaster = pair.second;
		}

	} );

	// 마스터를 찾지 못한 경우 파티는 종료 된다...
	if (0 == masterSeq || NULL == pReadyMaster)
	{
		DEBUGLOG("onTime_DUNGEON_BATTLE 0 == masterSeq || NULL == pReadyMaster");

		std::vector<User*> vec;
		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
			vec.push_back(pair.second);
		} );

		auto it = vec.begin();
		for(; it != vec.end(); ++it)
		{
			User * pUser = (*it);
			::Network::Packet * pLeave = ::Network::GETPACKETPOOL()->SEND_NEW();
			pLeave->MsgCat("%d%d", pUser->GetUserSeq(), 0);
			pLeave->MakePacket(CMD_SN_PARTY_LEAVE);
			pUser->Send(pLeave);

			NLogic::Space * pSpace = pUser->GetSpace();
			if (NULL != pSpace)
				pSpace->LeaveUser(*it);
		}
		vec.clear();
		return false;
	}

	std::for_each(_playUserTree.begin(), _playUserTree.end(), [&](const std::pair<int, User *> & pair) {

		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
		pNoti->MsgCat("%d", masterSeq);
		pNoti->MakePacket(CMD_SN_DUNGEON_DELEGATE_CHIEF);
		pair.second->Send(pNoti);

	} );

	// 마스터 위임
	_isChangeMaster = true;
	_master = pReadyMaster;

	return true;
}

void
Party::onTime_DUNGEON_BATTLE_CheckPlayer()
{
	USERTREE clsKickUserTree;
	unsigned long nowTime = ProjectZ::NLogic::NFunction::GetTickCount();

	std::for_each(_playUserTree.begin(), _playUserTree.end(), [&](const std::pair<int, User *> & pair) {
		if (nowTime - pair.second->GetLastLatency() > 1000 * 10)
		{
			clsKickUserTree[pair.first] = pair.second;
		}
	} );

	if (clsKickUserTree.size() == 0)
		return;

	// 10 초가 응답이 없던 유저들은 파티에서 나감을 알린다...
	std::for_each(clsKickUserTree.begin(), clsKickUserTree.end(), [&](const std::pair<int, User *> & pair) {

		// 파티에서 나간다고 통보....
		std::for_each(_playUserTree.begin(), _playUserTree.end(), [&](const std::pair<int, User *> & player_pair) {
			::Network::Packet * pLeave = ::Network::GETPACKETPOOL()->SEND_NEW();
			pLeave->MsgCat("%d%d", pair.second->GetUserSeq(), 0);
			pLeave->MakePacket(CMD_SN_PARTY_LEAVE);
			player_pair.second->Send(pLeave);
		} );

	} );

	// 던전 밖으로 이동 처리...
	std::for_each(clsKickUserTree.begin(), clsKickUserTree.end(), [&](const std::pair<int, User *> & pair) {
		pair.second->SetBattle_afterEffect();
		if (NULL != pair.second->GetSpace())
			pair.second->GetSpace()->LeaveUser(pair.second);
	} );


	clsKickUserTree.clear();
}

bool
Party::onTime_DUNGEON_CLEAR()
{
	return false;
}

bool
Party::onTime_NEW_PVP_ROOM_WAIT()
{
	DEBUGLOG("onTime_NEW_PVP_ROOM_WAIT");

	std::vector<User *> clsUserVector;

	std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](USERTREE::value_type & pair) {
		User * pUser = pair.second;
		clsUserVector.push_back(pUser);
	} );

	::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pNoti << static_cast<int16_t>(ACK_OK);
	pNoti->MakePacket(CMD_SC_PVP_ROOM_CANCEL);
	std::for_each(clsUserVector.begin(), clsUserVector.end(), [&](User * pUser) {
		pUser->SendOneshotEncrypt(pNoti);

		NLogic::Space * pSpace = pUser->GetSpace();
		if (NULL != pSpace)
			pSpace->LeaveUser(pUser);
	} );
	::Network::GETPACKETPOOL()->SEND_DEL(pNoti);
	clsUserVector.clear();

	return false;
}

bool
Party::onTime_PVP_ACCEPT_WAIT()
{
	DEBUGLOG("onTime_PVP_ACCEPT_WAIT");

	// 방장이 없다는 것은 상대가 PVP 신청을 거절한 경우.
	// 이미 방장도 상대가 거절 했을때 파티에서 나갔으므로, 패킷을 보내지 않는다.
	if (NULL == _master)
		return false;

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();

	*pAck << static_cast<int16_t>(ACK_MATCHING_FAIL);

	if (_master->GetEnumState() == User::EnumState::PVP_QUICK_WAIT)
	{
		pAck->MakePacket(CMD_SC_QUICK_MATCH_PLAYER);
	}
	else if (_master->GetEnumState() == User::EnumState::PVP_FRIENDLY_WAIT
			|| _master->GetEnumState() == User::EnumState::PVP_AMITY_WAIT)
	{
		pAck->MakePacket(CMD_SC_PVP_FRIEND_MATCH_REQ);
	}

	_master->Send(pAck);

	_master->SetEnumState(User::EnumState::__NONE__);

	NLogic::Space * pSpace = _master->GetSpace();
	if (NULL != pSpace)
		pSpace->LeaveUser(_master);

	return false;
}

bool
Party::onTime_PVP_ENTERROOM_WAIT()
{
	PROCESSLOG("onTime_PVP_ENTERROOM_WAIT : usercount=%d", _clsAllUserTree.size());

	USERTREE::const_iterator citer;
	int delayCount = 0;

	// 파티에 인원이 1명인 경우 지연 유저는 파티에 존재하는 유저의 상대방으로 지정
	if (1 == static_cast<int>(_clsAllUserTree.size()))
	{
		_pvpDelayUser = _clsAllUserTree.begin()->second->GetBattle()->GetData()._pvpOppUser;
	}
	else
	{
		for (citer = _clsAllUserTree.begin(); citer != _clsAllUserTree.end(); ++citer)
		{
			if (citer->second->GetLastLatency() + 10 * 1000 < NLogic::NFunction::GetTickCount())
			{
				delayCount++;
				_pvpDelayUser = citer->second;
			}
		}
	}

	PROCESSLOG("onTime_PVP_ENTERROOM_WAIT : DelayCount = %d", delayCount);

	if (NULL == _pvpDelayUser)
	{
//		this->SetState(NLogic::Party::State::PVP_READY_WAIT);
		return true;
	}

	// 모든 유저가 지연이면 대전 종료
	if (2 <= delayCount)
	{
		std::vector<User*> vec;
		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
			vec.push_back(pair.second);
		} );

		std::for_each(vec.begin(), vec.end(), [&](User * pUser) {
			_pvpDelayUser = pUser;

			pUser->GetBattle()->GetData().x 		= ConstPosX;
			pUser->GetBattle()->GetData().y		= ConstPosY;
			pUser->GetBattle()->GetData().degree	= ConstDegree;
			pUser->GetBattle()->GetData().bReadyFight = false;
			pUser->GetBattle()->GetData().bRecvEnterRoom = false;

			::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();

			*pNoti << static_cast<int16_t>(ACK_MATCHING_MASTER_GONE);
			*pNoti << pUser->GetUserSeq();
			*pNoti << static_cast<uint16_t>(1);			// exit_map_id(?)
			*pNoti << static_cast<uint16_t>(pUser->GetBattle()->GetData().x);
			*pNoti << static_cast<uint16_t>(pUser->GetBattle()->GetData().y);
			*pNoti << static_cast<uint16_t>(pUser->GetBattle()->GetData().degree);

			pNoti->MakePacket(CMD_SC_PVP_OUT_REQ);
			pUser->Send(pNoti);

			pUser->SetEnumState(User::EnumState::__NONE__);

			if (NULL != pUser->GetSpace())
			{
				pUser->GetSpace()->LeaveUser(pUser);
			}
		} );

//		for(; it != vec.end(); ++it)
//		{
//			(*it)->SetBattle_afterEffect();
//			(*it)->GetSpace()->LeaveUser(*it);
//		}
		vec.clear();

		return false;
	}

	// 지연 유저의 상대방에게 패킷 전송
	User * pOppUser = _pvpDelayUser->GetBattle()->GetData()._pvpOppUser;

	PROCESSLOG("onTime_PVP_ENTERROOM_WAIT : %x, %x", pOppUser, _pvpDelayUser);

	if (NULL == pOppUser)
	{
		_pvpDelayUser->GetBattle()->GetData().x 		= ConstPosX;
		_pvpDelayUser->GetBattle()->GetData().y			= ConstPosY;
		_pvpDelayUser->GetBattle()->GetData().degree	= ConstDegree;
		_pvpDelayUser->GetBattle()->GetData().bReadyFight = false;
		_pvpDelayUser->GetBattle()->GetData().bRecvEnterRoom = false;

		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();

		*pNoti << static_cast<int16_t>(ACK_MATCHING_MASTER_GONE);
		*pNoti << _pvpDelayUser->GetUserSeq();
		*pNoti << static_cast<uint16_t>(1);			// exit_map_id(?)
		*pNoti << static_cast<uint16_t>(_pvpDelayUser->GetBattle()->GetData().x);
		*pNoti << static_cast<uint16_t>(_pvpDelayUser->GetBattle()->GetData().y);
		*pNoti << static_cast<uint16_t>(_pvpDelayUser->GetBattle()->GetData().degree);

		pNoti->MakePacket(CMD_SC_PVP_OUT_REQ);
		_pvpDelayUser->Send(pNoti);

		_pvpDelayUser->SetEnumState(User::EnumState::__NONE__);

		if (NULL != _pvpDelayUser->GetSpace())
		{
			_pvpDelayUser->GetSpace()->LeaveUser(_pvpDelayUser);
		}

		return false;
	}

	::Network::Packet * pAck	= ::Network::GETPACKETPOOL()->SEND_NEW();

	*pAck << static_cast<uint8_t>(rand() % 4);
	*pAck << static_cast<uint16_t>(pOppUser->GetBattle()->GetData().degree);	// 방향 벡터(보고있는 방향 0 : RIGHT, 90 : DOWN..)
	*pAck << static_cast<uint16_t>(pOppUser->GetBattle()->GetData().x);
	*pAck << static_cast<uint16_t>(pOppUser->GetBattle()->GetData().y);
	*pAck << static_cast<uint16_t>(PVP_MAP_ID);	// 세팅될 맵

	PROCESSLOG("onTime_PVP_ENTERROOM_WAIT : SEND ENTER ROOM PACKET. userseq=%d", pOppUser->GetUserSeq());

	pAck->MakePacket(CMD_SN_ENTER_ROOM);
	pOppUser->Send(pAck);

	this->SetState(NLogic::Party::State::PVP_READY_WAIT);
	pOppUser->SetEnumState(User::EnumState::PVP_READY);

	return false;
}

bool
Party::onTime_PVP_READY_WAIT()
{
	PROCESSLOG("onTime_PVP_READY_WAIT : usercount=%d", _clsAllUserTree.size());

	USERTREE::const_iterator citer;
	int delayCount = 0;

	// 파티에 인원이 1명인 경우 지연 유저는 파티에 존재하는 유저의 상대방으로 지정
	if (1 == static_cast<int>(_clsAllUserTree.size()))
	{
		_pvpDelayUser = _clsAllUserTree.begin()->second->GetBattle()->GetData()._pvpOppUser;
	}
	else
	{
		for (citer = _clsAllUserTree.begin(); citer != _clsAllUserTree.end(); ++citer)
		{
			if (citer->second->GetLastLatency() + 10 * 1000 < NLogic::NFunction::GetTickCount())
			{
				delayCount++;
				_pvpDelayUser = citer->second;
			}
		}
	}

	PROCESSLOG("onTime_PVP_READY_WAIT : DelayCount=%d", delayCount);

	if (NULL == _pvpDelayUser)
	{
//		this->SetState(NLogic::Party::State::PVP_BATTLE);
		return true;
	}

	// 모든 유저가 지연이면 대전 종료
	if (2 <= delayCount)
	{
		std::vector<User*> vec;
		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
			vec.push_back(pair.second);
		} );

		std::for_each(vec.begin(), vec.end(), [&](User * pUser) {
			_pvpDelayUser = pUser;

			pUser->GetBattle()->GetData().x 		= ConstPosX;
			pUser->GetBattle()->GetData().y		= ConstPosY;
			pUser->GetBattle()->GetData().degree	= ConstDegree;
			pUser->GetBattle()->GetData().bReadyFight = false;
			pUser->GetBattle()->GetData().bRecvEnterRoom = false;

			::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();

			*pNoti << static_cast<int16_t>(ACK_MATCHING_MASTER_GONE);
			*pNoti << pUser->GetUserSeq();
			*pNoti << static_cast<uint16_t>(1);			// exit_map_id(?)
			*pNoti << static_cast<uint16_t>(ConstPosX);
			*pNoti << static_cast<uint16_t>(ConstPosY);
			*pNoti << static_cast<uint16_t>(ConstDegree);

			pNoti->MakePacket(CMD_SC_PVP_OUT_REQ);
			pUser->Send(pNoti);

			pUser->SetEnumState(User::EnumState::__NONE__);

			if (NULL != pUser->GetSpace())
			{
				pUser->GetSpace()->LeaveUser(pUser);
			}
		} );

//		auto it = vec.begin();
//		for(; it != vec.end(); ++it)
//		{
//			(*it)->SetBattle_afterEffect();
//			(*it)->GetSpace()->LeaveUser(*it);
//		}
		vec.clear();

		return false;
	}

	// 한명의 유저만 응답이 없는 경우 AI 위임
	// 지연 유저의 상대방에게 패킷 전송
	User * pOppUser = _pvpDelayUser->GetBattle()->GetData()._pvpOppUser;
	if (NULL == pOppUser)
		return false;

	// 응답 지연 유저는 CN_READY를 못받은 상태이므로 여기서 HP, SP를 보정한다.
	_pvpDelayUser->GetBattle()->GetData().userseq = _pvpDelayUser->GetUserSeq();

	int HP = NLogic::NFunction::GetMaxHP(_pvpDelayUser);
	_pvpDelayUser->GetBattle()->GetData().HP = (HP * NLogic::NFunction::GetAdjustHP(_pvpDelayUser)) / 100;
	_pvpDelayUser->GetBattle()->GetData().HP_MAX = _pvpDelayUser->GetBattle()->GetData().HP;

	int SP = NLogic::NFunction::GetMaxSP(_pvpDelayUser);
	_pvpDelayUser->GetBattle()->GetData().SP = SP;
	_pvpDelayUser->GetBattle()->GetData().SP_MAX = SP;

	{
		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
		pNoti->MakePacket(CMD_SN_FIGHT);
		pOppUser->Send(pNoti);

		PROCESSLOG("onTime_PVP_READY_WAIT : SEND SN_FIGHT PACKET. to user=%s", pOppUser->GetSocialID().c_str());
	}

	{
		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
		*pNoti << static_cast<uint8_t>(1);
		*pNoti << _pvpDelayUser->GetUserSeq();
		*pNoti << pOppUser->GetUserSeq();
		pNoti->MakePacket(CMD_SC_BATTLE_LATENCY_START);
		pOppUser->Send(pNoti);

		PROCESSLOG("onTime_PVP_READY_WAIT : SEND SC_BATTLE_LATENCY_START PACKET. to user=%s, delayuser=%s", pOppUser->GetSocialID().c_str(), _pvpDelayUser->GetSocialID().c_str());
	}

	this->SetState(NLogic::Party::State::PVP_BATTLE);
	pOppUser->SetEnumState(User::EnumState::PVP_BATTLE);

	return false;
}

bool
Party::onTime_PVP_BATTLE()
{
	DEBUGLOG("onTime_PVP_BATTLE");

	CreateHpBuff();

	USERTREE::const_iterator citer;

	int delayCount = 0;
	User * pDelayUser = NULL;

	for (citer = _clsAllUserTree.begin(); citer != _clsAllUserTree.end(); ++citer)
	{
		if (citer->second->GetLastLatency() + 1000 < NLogic::NFunction::GetTickCount())
		{
			delayCount++;
			pDelayUser = citer->second;
		}
	}

	// 두명 모두 지연인 경우
	if (delayCount >= 2)
	{
		return true;
	}

	// 1명 남은 상태에서 지연이 없는 경우 (정상)
	if (1 >= static_cast<int>(_clsAllUserTree.size()) && 0 >= delayCount)
	{
		return true;
	}

	// 1명만 남은 상태에서 응답지연인 경우 PVP 종료
	if (1 >= static_cast<int>(_clsAllUserTree.size()) && 1 >= delayCount)
	{
		std::vector<User*> vec;
		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
			vec.push_back(pair.second);
		} );

		std::for_each(vec.begin(), vec.end(), [&](User * pUser) {
			_pvpDelayUser = pUser;

			pUser->GetBattle()->GetData().x 		= ConstPosX;
			pUser->GetBattle()->GetData().y		= ConstPosY;
			pUser->GetBattle()->GetData().degree	= ConstDegree;
			pUser->GetBattle()->GetData().bReadyFight = false;
			pUser->GetBattle()->GetData().bRecvEnterRoom = false;

			::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();

			*pNoti << static_cast<int16_t>(ACK_MATCHING_MASTER_GONE);
			*pNoti << pUser->GetUserSeq();
			*pNoti << static_cast<uint16_t>(1);			// exit_map_id(?)
			*pNoti << static_cast<uint16_t>(ConstPosX);
			*pNoti << static_cast<uint16_t>(ConstPosY);
			*pNoti << static_cast<uint16_t>(ConstDegree);

			pNoti->MakePacket(CMD_SC_PVP_OUT_REQ);
			pUser->Send(pNoti);

			pUser->SetEnumState(User::EnumState::__NONE__);

			if (NULL != pUser->GetSpace())
			{
				pUser->GetSpace()->LeaveUser(pUser);
			}
		} );

		vec.clear();

		return false;
	}

	// 패킷 지연 유저가 없고, 현재 AI 위임 상태가 아닌 경우. (정상)
	if (NULL == pDelayUser && NULL == _pvpDelayUser)
	{
		return true;
	}

	// 패킷 지연 유저가 없고, 현재 AI 위임 상태인 경우 AI 위임 해제
	if (NULL == pDelayUser && NULL != _pvpDelayUser)
	{
		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
		*pNoti << static_cast<uint8_t>(1);
		*pNoti << _pvpDelayUser->GetUserSeq();
		*pNoti << static_cast<uint16_t>(_pvpDelayUser->GetBattle()->GetData().x);
		*pNoti << static_cast<uint16_t>(_pvpDelayUser->GetBattle()->GetData().y);

		for (citer = _clsAllUserTree.begin(); citer != _clsAllUserTree.end(); ++citer)
		{
			if (_pvpDelayUser == citer->second)
				continue;

			pNoti->MakePacket(CMD_SC_BATTLE_LATENCY_STOP);
			citer->second->SendOneshotEncrypt(pNoti);
			break;
		}

		::Network::GETPACKETPOOL()->SEND_DEL(pNoti);
//		_pvpDelayUser->CancelBattle_afterEffect();
		_pvpDelayUser = NULL;
		return true;
	}

	// 패킷 지연 유저가 있고, 현재 AI 위임 상태가 아닌 경우는 패킷 지연 유저에 대해 AI 위임
	if (NULL != pDelayUser && NULL == _pvpDelayUser)
	{
		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
		*pNoti << static_cast<uint8_t>(1);
		*pNoti << pDelayUser->GetUserSeq();

		for (citer = _clsAllUserTree.begin(); citer != _clsAllUserTree.end(); ++citer)
		{
			if (pDelayUser == citer->second)
				continue;

			*pNoti << citer->second->GetUserSeq();
			pNoti->MakePacket(CMD_SC_BATTLE_LATENCY_START);
			citer->second->SendOneshotEncrypt(pNoti);
			break;
		}

		::Network::GETPACKETPOOL()->SEND_DEL(pNoti);
		_pvpDelayUser = pDelayUser;
//		_pvpDelayUser->SetBattle_afterEffect();

		return true;
	}

	// 패킷 지연 유저가 있고, 현재 AI 위임 상태이고, 현재 지연 유저가 기존 지연 유저가 아닌 경우 AI 위임 변경
	if (NULL != pDelayUser && NULL != _pvpDelayUser && pDelayUser != _pvpDelayUser)
	{
		{
			::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
			*pNoti << static_cast<uint8_t>(1);
			*pNoti << _pvpDelayUser->GetUserSeq();
			*pNoti << static_cast<uint16_t>(_pvpDelayUser->GetBattle()->GetData().x);
			*pNoti << static_cast<uint16_t>(_pvpDelayUser->GetBattle()->GetData().y);
			pNoti->MakePacket(CMD_SC_BATTLE_LATENCY_STOP);
			pDelayUser->Send(pNoti);
		}

		{
			::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
			*pNoti << static_cast<uint8_t>(1);
			*pNoti << pDelayUser->GetUserSeq();
			*pNoti << _pvpDelayUser->GetUserSeq();
			pNoti->MakePacket(CMD_SC_BATTLE_LATENCY_START);
			_pvpDelayUser->Send(pNoti);
		}

		_pvpDelayUser = pDelayUser;
	}

	return true;
}

bool
Party::onTime_PK_ACCEPT_WAIT()
{
	DEBUGLOG("onTime_PK_ACCEPT_WAIT");

	// 이 경우는 경기를 시작해야 한다...
	if (_clsAcceptUserTree.size() > static_cast<size_t>(MIN_PK_INVITE))
	{
		int pos_x[4] = { 31*32, 42*32, 19*32, 10*32 };
		int pos_y[4] = { 13*32, 21*32, 27*32, 15*32 };
		int degree[4] = { 90, 180, 270, 0 };

		auto userTreeItr = _space->GetUserTree().begin();
		for ( int i = 0 ; userTreeItr != _space->GetUserTree().end() ; ++userTreeItr, i++ )
		{
			User * pOther = userTreeItr->second;
			pOther->Set_PK_Coordinate( pos_x[i], pos_y[i], degree[i] );
		}

		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
		* pNoti << static_cast<uint64_t>(_space->GetData()._index);
		pNoti->MakePacket(CMD_SC_REQ_PK_ENTER);
		_space->SendAll(pNoti);

		this->SetState(NLogic::Party::State::PK_ENTER_WAIT);
/*
		std::vector<User*> vec;
		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
			auto itr = _clsAcceptUserTree.find(pair.first);
			if (itr == _clsAcceptUserTree.end())
				vec.push_back(pair.second);
		} );

		auto it = vec.begin();
		for(; it != vec.end(); ++it)
		{
			this->LeaveUser(*it);
		}
		vec.clear();
*/
		return false;
	}

	return this->onTime_PK_CANCEL();
}

bool
Party::onTime_PK_CANCEL()
{
	DEBUGLOG("onTime_PK_CANCEL");

	::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
	*pNoti << static_cast<uint16_t>(ACK_OK);
	pNoti->MakePacket(CMD_SC_PK_CANCEL_INVITATION_PARTY);

	std::vector<User*> vec;
	// 이미 accept 를 한 유저는 스페이스에서 빼야 함
	std::for_each(_clsAcceptUserTree.begin(), _clsAcceptUserTree.end(), [&](const std::pair<int, User *> & pair) {
		vec.push_back(pair.second);
		pair.second->SendOneshotEncrypt(pNoti);
	} );

	auto it = vec.begin();
	for(; it != vec.end(); ++it)
	{
		(*it)->SetEnumState(User::EnumState::BATTLE_ROYAL_END);
		if (NULL != (*it)->GetSpace())
			(*it)->GetSpace()->LeaveUser(*it);// 스페이스에서 빠지면 파티에서도 빠짐(상태도 __NONE__ 변경됨)
	}
	vec.clear();

	// accept 안한 유저는 파티에서만 빼면 됨.
	std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
		pair.second->SetEnumState(User::EnumState::__NONE__);
		vec.push_back(pair.second);
		pair.second->SendOneshotEncrypt(pNoti);
	} );

	::Network::GETPACKETPOOL()->SEND_DEL(pNoti);

	it = vec.begin();
	for(; it != vec.end(); ++it)
	{
		this->LeaveUser(*it);
	}

	return false;
}

bool
Party::onTime_PK_READY_WAIT()
{
	DEBUGLOG("onTime_PK_READY_WAIT");
	if( State::PK_READY_WAIT == this->_state )
	{
		DEBUGLOG("onTime_PK_READY_WAIT");
		::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
		*pNoti << static_cast<uint16_t>(MAX_PK_TIME);
		pNoti->MakePacket(CMD_SN_PK_START);

		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](const std::pair<int, User *> & pair) {
			NLogic::Equip * pUserEquip = pair.second->GetEquip();
			if (NULL != pUserEquip)
			{
				// 전투펫을 장착하고 있다면 스태미너 감소
				if (true == pUserEquip->IsExistItem(ITEM_EQUIP_POS_PET))
				{
					pUserEquip->GetItem(ITEM_EQUIP_POS_PET)->DecreaseBattlepetStamina();
				}
			}

			if(User::EnumState::BATTLE_ROYAL_BATTLE != pair.second->GetEnumState())
			{
				NLogic::Battle * pBattleRoyalBattle = pair.second->GetBattleRoyalBattle();

				// 응답 지연 유저는 CS_PK_READY를 못 받은 상태 이므로 여기서 HP 보정
				if (NULL != pBattleRoyalBattle)
				{
					pBattleRoyalBattle->GetData().isAI = true;

					int HP = NLogic::NFunction::GetMaxHP(pair.second);
					pBattleRoyalBattle->GetData().HP = (HP * NLogic::NFunction::GetAdjustHP(pair.second, false)) / 100;
					pBattleRoyalBattle->GetData().HP_MAX = pBattleRoyalBattle->GetData().HP;

					int SP = NLogic::NFunction::GetMaxSP(pair.second);
					pBattleRoyalBattle->GetData().SP = SP;
					pBattleRoyalBattle->GetData().SP_MAX = SP;
				}

				_clsPKDelayUserVectorOld.push_back(pair.second);
			}
			else
				pair.second->SendOneshotEncrypt(pNoti, 1);
		} );
		::Network::GETPACKETPOOL()->SEND_DEL(pNoti);

		this->SetState(NLogic::Party::State::PK_BATTLE);
	}
	return false;
}

bool
Party::onTime_PK_BATTLE()
{
	if( State::PK_BATTLE == _state )
	{
		DEBUGLOG("onTime_PK_BATTLE");

		CreateHpBuff();

		std::for_each(_space->GetBattleTree().begin(), _space->GetBattleTree().end(), [&](Space::BATTLETREE::value_type &pair){
			if (time(NULL) > pair.second->GetData().rebirthIntervalTime && 0 != pair.second->GetData().rebirthIntervalTime)
			{
				pair.second->GetData().rebirthIntervalTime = 0;
				pair.second->GetData().HP = pair.second->GetData().HP_MAX;
				_space->GetData()._aliveUserCount++;

				::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
				*pNoti << pair.first;
				DEBUGLOG("CMD_SN_PK_REBIRTH user_seq : %d", pair.first);
				pNoti->MakePacket(CMD_SN_PK_REBIRTH);
				_space->SendAll(pNoti);
			}
		});

		std::vector<User *> kickUserVector;
		std::vector<User *> nomalUserVector;

		std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](USERTREE::value_type & pair) {
			if (pair.second->GetLastLatency() + 1000 * 10 < NLogic::NFunction::GetTickCount())
				kickUserVector.push_back(pair.second);
			else if (pair.second->GetLastLatency() + 1000 < NLogic::NFunction::GetTickCount())
				_clsPKDelayUserVectorNew.push_back(pair.second);
			else
				nomalUserVector.push_back(pair.second);
		} );

		// User Kick
		std::for_each(kickUserVector.begin(), kickUserVector.end(), [&](User * pUser){
			NLogic::Space * pSpace = pUser->GetSpace();
			if( NULL != pSpace )
			{
				DEBUGLOG("the2 %d \t Kick 유저 %d",__LINE__, pUser->GetUserSeq());
				pUser->SetBattle_afterEffect();
				pUser->SetEnumState(User::EnumState::BATTLE_ROYAL_END);
				pSpace->LeaveUser(pUser);
			}
		});
		// User Kick

		if (_clsPKDelayUserVectorNew.size() >= 3)
		{
			return true;
		}

		if (nomalUserVector.size() <= 0)
		{
			return true;
		}

		if (NULL == _pkAIPlayUser)
			_pkAIPlayUser = ( * nomalUserVector.begin());


		// AI Stop Process
		std::vector<User * > realNormaldelayUser;
		std::for_each(nomalUserVector.begin(), nomalUserVector.end(), [&](User * pUser){
			NLogic::Battle * pBattle = pUser->GetBattleRoyalBattle();
			if (NULL != pBattle && true == pBattle->GetData().isAI)
				realNormaldelayUser.push_back(pUser);
		} );

		if (realNormaldelayUser.size() > 0)
		{
			::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
			*pNoti << static_cast<uint8_t>(realNormaldelayUser.size());
			std::for_each(realNormaldelayUser.begin(), realNormaldelayUser.end(), [&](User * pUser){
				NLogic::Battle * pBattleRoyalBattle = pUser->GetBattleRoyalBattle();
				if (NULL != pBattleRoyalBattle)
				{
					DEBUGLOG("the2 %d \t 딜레이 Stop 유저 %d",__LINE__, pUser->GetUserSeq());
					*pNoti << pUser->GetUserSeq();
					*pNoti << static_cast<uint16_t>(pUser->GetBattleRoyalBattle()->GetData().x);
					*pNoti << static_cast<uint16_t>(pUser->GetBattleRoyalBattle()->GetData().y);

					pUser->GetBattleRoyalBattle()->GetData().isAI = false;
				}
			} );
			pNoti->MakePacket(CMD_SC_BATTLE_LATENCY_STOP);
				DEBUGLOG("the2 %d A.I Stop 유저 %d",__LINE__, _pkAIPlayUser->GetUserSeq());
			_pkAIPlayUser->Send(pNoti);
		}
		// AI Stop Process


		// AI Change AI Master
		std::vector<User * > oldDelayUser;
		User * pOldAIPlayer = _pkAIPlayUser;
		std::for_each(_clsPKDelayUserVectorNew.begin(), _clsPKDelayUserVectorNew.end(), [&](User * pUser){
			if (pUser == _pkAIPlayUser)
			{
				_pkAIPlayUser = ( * nomalUserVector.begin());

				std::for_each(_clsPKDelayUserVectorOld.begin(), _clsPKDelayUserVectorOld.end(), [&](User * pUser){
					oldDelayUser.push_back(pUser);
				});
			}
		} );

		if (oldDelayUser.size() > 0)
		{
			::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
			*pNoti << static_cast<uint8_t>(oldDelayUser.size());
			std::for_each(oldDelayUser.begin(), oldDelayUser.end(), [&](User * pUser){
				DEBUGLOG("the2 %d \t 딜레이 Stop 유저 %d",__LINE__, pUser->GetUserSeq());
				*pNoti << pUser->GetUserSeq();
				*pNoti << static_cast<uint16_t>(pUser->GetBattleRoyalBattle()->GetData().x);
				*pNoti << static_cast<uint16_t>(pUser->GetBattleRoyalBattle()->GetData().y);
			} );
			pNoti->MakePacket(CMD_SC_BATTLE_LATENCY_STOP);
				DEBUGLOG("the2 %d A.I Stop 유저 %d",__LINE__, pOldAIPlayer->GetUserSeq());
			pOldAIPlayer->Send(pNoti);
		}
		// AI Change AI Master



		// AI Start Process
		std::vector<User * > delayUser;
		std::for_each(_clsPKDelayUserVectorNew.begin(), _clsPKDelayUserVectorNew.end(), [&](User * pUser){
			NLogic::Battle * pBattle = pUser->GetBattleRoyalBattle();
			if (NULL != pBattle && false == pBattle->GetData().isAI)
				delayUser.push_back(pUser);
		} );

		if (delayUser.size() > 0)
		{
			::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
			*pNoti << static_cast<uint8_t>(delayUser.size() + oldDelayUser.size());
			std::for_each(delayUser.begin(), delayUser.end(), [&](User * pUser){
				DEBUGLOG("the2 %d \t 딜레이 유저 %d",__LINE__, pUser->GetUserSeq());
				*pNoti << pUser->GetUserSeq();
				pUser->GetBattleRoyalBattle()->GetData().isAI = true;
			});
			std::for_each(oldDelayUser.begin(), oldDelayUser.end(), [&](User * pUser){
				DEBUGLOG("the2 %d \t old 딜레이 유저 %d",__LINE__, pUser->GetUserSeq());
				*pNoti << pUser->GetUserSeq();
			});
				DEBUGLOG("the2 %d A.I Start 유저 %d",__LINE__, _pkAIPlayUser->GetUserSeq());
			*pNoti << _pkAIPlayUser->GetUserSeq();
			pNoti->MakePacket(CMD_SC_BATTLE_LATENCY_START);
			_pkAIPlayUser->Send(pNoti);
		}
		// AI Start Process


		_clsPKDelayUserVectorOld.clear();
		_clsPKDelayUserVectorOld = _clsPKDelayUserVectorNew;
		_clsPKDelayUserVectorNew.clear();


//		USERTREE delayUserTree;
//		// 현재 지연 유저 찾기
//		USERTREE::const_iterator citer = _clsAllUserTree.begin();
//
//		std::vector<User *> kickUserVector;
//		std::vector<User *> delayUserVector;
//		for (; citer != _clsAllUserTree.end(); ++citer)
//		{
//			if (citer->second->GetLastLatency() + 1000 * 10 < NLogic::NFunction::GetTickCount())
//				kickUserVector.push_back(citer->second);
//
//			if (citer->second->GetLastLatency() + 1000 < NLogic::NFunction::GetTickCount())
//			{
//				delayUserTree[citer->first] = citer->second;
//			}
//		}
//
//		std::for_each(kickUserVector.begin(), kickUserVector.end(), [&](User * pUser){
//			NLogic::Space * pSpace = pUser->GetSpace();
//			if( NULL != pSpace )
//			{
//				pUser->SetBattle_afterEffect();
//				pUser->SetEnumState(User::EnumState::BATTLE_ROYAL_END);
//				pSpace->LeaveUser(pUser);
//			}
//		});
//
//		// 패킷 지연 유저가 없고, 현재 AI 위임 상태가 아닌 경우. (정상)
//		if (delayUserTree.empty() && _pkAIPlayUser == NULL)
//			return true;
//
//		// 패킷 지연 유저가 있고, 현재 AI 위임 상태가 아닌 경우는 패킷 지연 유저에 대해 AI 위임
//		if (!delayUserTree.empty() && NULL == _pkAIPlayUser)
//		{
//			Start_AI_PK(delayUserTree);
//			return true;
//		}
//
//		// 패킷 지연 유저가 없고, 현재 AI 위임 상태인 경우 AI 위임 해제
//		if (delayUserTree.empty() && NULL != _pkAIPlayUser)
//		{
//			AllStop_AI_PK();
//			return true;
//		}
//
//		// 패킷 지연 유저가 있고, 현재 AI 위임 상태인 경우.
//		if (!delayUserTree.empty() && NULL != _pkAIPlayUser)
//		{
//			if( _pkDelayUserTree == delayUserTree )
//				return true;
//			auto iterDelay = delayUserTree.find(_pkAIPlayUser->GetUserSeq());
//			if(delayUserTree.end() != iterDelay)
//				AllStop_AI_PK();
//			else
//				Stop_AI_PK(delayUserTree);
//			Start_AI_PK(delayUserTree);
//
//			return true;
//		}
	}
	return true;
}

void
Party::Start_AI_PK(USERTREE & delayUserTree)
{
	::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
	*pNoti << static_cast<uint8_t>(delayUserTree.size());

	auto iterDelay = delayUserTree.begin();
	for(; iterDelay != delayUserTree.end(); ++iterDelay)
	{
		DEBUGLOG("\tA.I start Delay user = %d", iterDelay->first );
		*pNoti << iterDelay->second->GetUserSeq();
	}

	auto iter = _clsAllUserTree.begin();
	for (; iter != _clsAllUserTree.end(); ++iter)
	{
		iterDelay = delayUserTree.find(iter->first);
		if(delayUserTree.end() != iterDelay)
			continue;
		else
		{
			DEBUGLOG("A.I start play user = %d", iter->second->GetUserSeq());
			if( NULL == _pkAIPlayUser )
				_pkAIPlayUser = iter->second;
			_pkDelayUserTree.clear();
			_pkDelayUserTree = delayUserTree;
			*pNoti << _pkAIPlayUser->GetUserSeq();
			pNoti->MakePacket(CMD_SC_BATTLE_LATENCY_START);
			_pkAIPlayUser->Send(pNoti);
			break;
		}
	}
}

void
Party::Stop_AI_PK(USERTREE & delayUserTree)
{
	// 패킷 지연이 풀린 유저를 stop
	USERTREE stopUserTree;
	auto iter = _pkDelayUserTree.begin();
	for(; iter != _pkDelayUserTree.end(); ++iter )
	{
		auto delayIter = delayUserTree.find(iter->first);
		if( delayIter != delayUserTree.end() )
			continue;

		stopUserTree[iter->first] = iter->second;
	}

	if( stopUserTree.empty() )
		return;

	::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
	*pNoti << static_cast<uint8_t>(stopUserTree.size());
	auto iterDelay = stopUserTree.begin();
	for(; iterDelay != stopUserTree.end(); ++iterDelay)
	{
		DEBUGLOG("\tA.I stop Delay user = %d", iterDelay->first );
		*pNoti << iterDelay->second->GetUserSeq();
		*pNoti << static_cast<uint16_t>(iterDelay->second->GetBattle()->GetData().x);
		*pNoti << static_cast<uint16_t>(iterDelay->second->GetBattle()->GetData().y);
	}

	DEBUGLOG("A.I stop play user = %d", _pkAIPlayUser->GetUserSeq());
	pNoti->MakePacket(CMD_SC_BATTLE_LATENCY_STOP);
	_pkAIPlayUser->Send(pNoti);
	_pkDelayUserTree.clear();
	_pkDelayUserTree = stopUserTree;
}

void
Party::AllStop_AI_PK()
{
	::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
	*pNoti << static_cast<uint8_t>(_pkDelayUserTree.size());
	auto iterDelay = _pkDelayUserTree.begin();
	for(; iterDelay != _pkDelayUserTree.end(); ++iterDelay)
	{
		DEBUGLOG("\tA.I stop Delay user = %d", iterDelay->first );
		*pNoti << iterDelay->second->GetUserSeq();
		*pNoti << static_cast<uint16_t>(iterDelay->second->GetBattle()->GetData().x);
		*pNoti << static_cast<uint16_t>(iterDelay->second->GetBattle()->GetData().y);
	}

	DEBUGLOG("A.I stop play user = %d", _pkAIPlayUser->GetUserSeq());
	pNoti->MakePacket(CMD_SC_BATTLE_LATENCY_STOP);
	_pkAIPlayUser->Send(pNoti);
	_pkAIPlayUser = NULL;
	_pkDelayUserTree.clear();
}

bool
Party::onTime_PK_END()
{
	if(NULL == _space)
		return false;

	std::vector<User*> & vec = _space->GetPKOutPlayUserVector();
	DEBUGLOG("PK_END PKOutPlayUserVector size : %d", vec.size());
	std::for_each(vec.begin(), vec.end(), [&](User * pUser){
		NLogic::Space * pSpace = pUser->GetSpace();
		pUser->SetEnumState(User::EnumState::BATTLE_ROYAL_END);

		if (NULL != pSpace)
		{
			DEBUGLOG("%s NULL != pSpace GID : %d POINTER : %x", __FUNCTION__, pUser->GetUserSeq(), pUser);
			pSpace->LeaveUser(pUser);
		}
		else
		{
			DEBUGLOG("%s NULL == pSpace GID : %d POINTER : %x", __FUNCTION__, pUser->GetUserSeq(), pUser);
		}
	});
	vec.clear();

	DEBUGLOG("OFF PK_END Timer!!!");
	return false;
}

bool
Party::onTime_New_Party_Room()
{
	// 매칭이 되지 않은 경우 이므로 파티 캔슬.....
	//_space->GetData()._maxUser
	/*
	 * SN_DUNGEON_PARTY_CANCLE		0x1128
	{
	   s16 sAck;
	}
	 */

	std::vector<User *> clsUserVector;

	std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](USERTREE::value_type & pair) {
		User * pUser = pair.second;
		clsUserVector.push_back(pUser);
	} );

	::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pNoti << static_cast<int16_t>(ACK_OK);
	pNoti->MakePacket(CMD_SN_DUNGEON_PARTY_CANCLE);
	std::for_each(clsUserVector.begin(), clsUserVector.end(), [&](User * pUser) {
		pUser->SendOneshotEncrypt(pNoti);

		NLogic::Space * pSpace = pUser->GetSpace();
		if (NULL != pSpace)
			pSpace->LeaveUser(pUser);
	} );
	::Network::GETPACKETPOOL()->SEND_DEL(pNoti);
	clsUserVector.clear();

	return false;
}

bool
Party::onTime_WORLDBOSS_WAIT()
{
	// 매칭이 되지 않은 경우 이므로 파티 캔슬.....
	//_space->GetData()._maxUser
	/*
	 SN_WORLD_BOSS_PARTY_CANCLE			0x4006
	{
	   s16 sAck;
	}
	 */

	DEBUGLOG("%s", __FUNCTION__);
	std::vector<User *> clsUserVector;

	std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](USERTREE::value_type & pair) {
		User * pUser = pair.second;
		clsUserVector.push_back(pUser);
	} );

	::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pNoti << static_cast<int16_t>(ACK_OK);
	pNoti->MakePacket(CMD_SN_WORLD_BOSS_PARTY_CANCLE);
	std::for_each(clsUserVector.begin(), clsUserVector.end(), [&](User * pUser) {
		pUser->SendOneshotEncrypt(pNoti);

		NLogic::Space * pSpace = pUser->GetSpace();
		if (NULL != pSpace)
			pSpace->LeaveUser(pUser);
	} );
	::Network::GETPACKETPOOL()->SEND_DEL(pNoti);
	clsUserVector.clear();

	return false;
}

bool
Party::onTime_WORLDBOSS_WAIT_FRIEND()
{
	// 매칭이 되지 않은 경우 이므로 파티 캔슬.....
	//_space->GetData()._maxUser
	/*
	 SN_WORLD_BOSS_PARTY_CANCLE			0x4006
	{
	   s16 sAck;
	}
	 */

	DEBUGLOG("%s", __FUNCTION__);
	std::vector<User *> clsUserVector;

	std::for_each(_clsAllUserTree.begin(), _clsAllUserTree.end(), [&](USERTREE::value_type & pair) {
		User * pUser = pair.second;
		clsUserVector.push_back(pUser);
	} );

	::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pNoti << static_cast<int16_t>(ACK_OK);
	pNoti->MakePacket(CMD_SN_WORLD_BOSS_PARTY_CANCLE);
	std::for_each(clsUserVector.begin(), clsUserVector.end(), [&](User * pUser) {
		pUser->SendOneshotEncrypt(pNoti);

		NLogic::Space * pSpace = pUser->GetSpace();
		if (NULL != pSpace)
			pSpace->LeaveUser(pUser);
	} );
	::Network::GETPACKETPOOL()->SEND_DEL(pNoti);
	clsUserVector.clear();

	return false;
}

bool
Party::onTime_HEAL_BUFF()
{
	if (NULL == _space)
		return false;

	if (NULL == _healBuffBattle)
		return false;

	_healBuffTotalTimeCount++;

	// 모든 유저에게 특정 시간동안 매초 마다 ZNO_SN_REQ_USER_HPSP_INFO로 버프를 획득한 유저의 hp싱크를 맞춰줌
	NLogic::Battle::Data & clsBattleData = _healBuffBattle->GetData();

	int targethp = 0;
	int targetsp = 0;

	if (clsBattleData.HP <= 0 )
		return true;

	int hp_gap = 0;
	if (State::PVP_BATTLE == _state)
		hp_gap = (clsBattleData.HP_MAX * NResource::Static::Instance().GetBalance()->GetValue(PVP_HEAL_BUFF_VALUE)) / 100;

	if (State::PK_BATTLE == _state)
		hp_gap = (clsBattleData.HP_MAX * NResource::Static::Instance().GetBalance()->GetValue(PK_HEAL_BUFF_VALUE)) / 100;

	clsBattleData.HP += hp_gap;
	if( clsBattleData.HP < 1 )
		clsBattleData.HP = 1;
	else if( clsBattleData.HP > clsBattleData.HP_MAX)
		clsBattleData.HP = clsBattleData.HP_MAX;

	int sp_gap = 0;
	clsBattleData.SP += sp_gap;
	if( clsBattleData.SP < 1 )
		clsBattleData.SP = 1;
	else if( clsBattleData.SP > clsBattleData.SP_MAX)
		clsBattleData.SP = clsBattleData.SP_MAX;

	targethp = clsBattleData.HP;
	targetsp = clsBattleData.SP;

	::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();

	*pNoti	<< static_cast<uint32_t>(_healBuffBattle->GetData().userseq)
			<< targethp << targetsp << static_cast<uint8_t>(0);
	pNoti->MakePacket(CMD_SN_HP_BUFF_INFO);

	_space->SendAll(pNoti);

	int healBuffTotalTime = 0;
	if (State::PVP_BATTLE == _state)
		healBuffTotalTime = NResource::Static::Instance().GetBalance()->GetValue(EnumBalance::PVP_HEAL_BUFF_TOTAL_TIME);

	if (State::PK_BATTLE == _state)
		healBuffTotalTime = NResource::Static::Instance().GetBalance()->GetValue(EnumBalance::PK_HEAL_BUFF_TOTAL_TIME);

	if (_healBuffTotalTimeCount >= healBuffTotalTime)
	{
		_healBuffBattle = NULL;
		_healBuffTotalTimeCount = 0;
		return false;
	}

	return true;
}

bool
Party::IsPVPDelayUser(User * pUser)
{
	if (NULL == _pvpDelayUser)
		return false;

	if (pUser == _pvpDelayUser)
		return true;

	return false;
}

bool
Party::checkTimeout()
{
	if (_clsAllUserTree.size() <= 1)
		return false;

	return true;
}

void
Party::CreateHpBuff()
{
/*
	// 버프오브젝트 생성
	SN_CREATE_HP_BUFF	0x142c
	{
		u32	u32Seq;		// 오브젝트 고유키
		u16	u16posX;	/// 월드포지션 X
		u16	u16posY;	/// 월드포지션 Y
	}
*/
	if (false == NResource::Static::Instance().GetContentsOpenResource()->IsOpen(HP_POTION))
		return;

	if (NULL == _space)
		return;

	int coolTime = 0;

	if (State::PVP_BATTLE == _state)
		coolTime = NResource::Static::Instance().GetBalance()->GetValue(EnumBalance::PVP_HEAL_BUFF_APPEAR_COOLTIME);

	if (State::PK_BATTLE == _state)
		coolTime = NResource::Static::Instance().GetBalance()->GetValue(EnumBalance::PK_HEAL_BUFF_APPEAR_COOLTIME);

	if (0 == coolTime)
		return;

	// 물약 버프가 생성 후 남아있는 경우
	if (0 < _createHpBuffKey)
		return;

	// 물약 생성 쿨타임 시간이 안된 경우
	if (coolTime > _createHpBuffCoolTimeCount)
	{
		_createHpBuffCoolTimeCount++;
		return;
	}

	// 물약 생성
	int index = NResource::Static::Instance().GetPvpPkBuffPositionResource()->GetRandomFlyIndex();

	if (-1 == index)
		return;

	_createHpBuffCoolTimeCount	= 0;
	_createHpBuffKey		= time(NULL);

	auto pFly = NResource::Static::Instance().GetPvpPkBuffPositionResource()->GetFly(index);
	::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pNoti << static_cast<uint32_t>(_createHpBuffKey);

	if (State::PVP_BATTLE == _state)
	{
		* pNoti	<< static_cast<uint16_t>(pFly->_PVP_X)
							<< static_cast<uint16_t>(pFly->_PVP_Y);
	}
	if (State::PK_BATTLE == _state)
	{
		* pNoti	<< static_cast<uint16_t>(pFly->_PK_X)
							<< static_cast<uint16_t>(pFly->_PK_Y);
	}
	pNoti->MakePacket(CMD_SN_CREATE_HP_BUFF);
	_space->SendAll(pNoti);
}

void
Party::SetHealBuff(User * pUser)
{
	int interval = 0;
	if (State::PVP_BATTLE == _state)
	{
		_healBuffBattle = pUser->GetBattle();
		interval = NResource::Static::Instance().GetBalance()->GetValue(EnumBalance::PVP_HEAL_BUFF_PER_TIME);
	}

	if (State::PK_BATTLE == _state)
	{
		_healBuffBattle = pUser->GetBattleRoyalBattle();
		interval = NResource::Static::Instance().GetBalance()->GetValue(EnumBalance::PK_HEAL_BUFF_PER_TIME);
	}

	if (0 == interval)
		return;

	this->setTimer(interval * 1000, static_cast<int>(State::HEAL_BUFF));
}

} /*NLogic*/ } /* namespace ProjectZ */
